package com.canaan.business.service.bill.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.canaan.business.common.enums.inOutStock.InOrderStatusEnum;
import com.canaan.business.common.enums.inOutStock.InStockOrderTypeEnum;
import com.canaan.business.domain.basic.WmsProduct;
import com.canaan.business.domain.bill.RefundProductBill;
import com.canaan.business.domain.bill.RefundProductBillDetail;
import com.canaan.business.domain.inOutStock.WmsInStockDetailOrder;
import com.canaan.business.domain.inOutStock.WmsInStockOrder;
import com.canaan.business.domain.vo.RefundProductBillExportVo;
import com.canaan.business.domain.vo.RefundProductBillVo;
import com.canaan.business.mapper.bill.RefundProductBillMapper;
import com.canaan.business.service.basic.IWmsProductService;
import com.canaan.business.service.bill.IRefundProductBillDetailService;
import com.canaan.business.service.bill.IRefundProductBillService;
import com.canaan.business.service.inOutStock.IWmsInStockDetailOrderService;
import com.canaan.business.service.inOutStock.IWmsInStockOrderService;
import com.canaan.common.constant.PrefixConstants;
import com.canaan.common.exception.ServiceException;
import com.canaan.common.utils.DateUtils;
import com.canaan.common.utils.SecurityUtils;
import com.canaan.common.utils.StringUtils;
import com.canaan.common.utils.TableNoUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 退料单Service业务层处理
 *
 * @author ruoyi
 * @date 2023-01-31
 */
@Service
public class RefundProductBillServiceImpl implements IRefundProductBillService {
    @Resource
    private RefundProductBillMapper refundProductBillMapper;
    @Resource
    private IRefundProductBillDetailService refundProductBillDetailService;
    @Resource
    private IWmsInStockOrderService wmsInStockOrderService;
    @Resource
    private IWmsInStockDetailOrderService wmsInStockDetailOrderService;
    @Resource
    private IWmsProductService wmsProductService;

    /**
     * 查询退料单
     *
     * @param id 退料单主键
     * @return 退料单
     */
    @Override
    public RefundProductBill selectRefundProductBillById(Long id) {
        return refundProductBillMapper.selectRefundProductBillById(id);
    }

    /**
     * 查询退料单列表
     *
     * @param refundProductBill 退料单
     * @return 退料单
     */
    @Override
    public List<RefundProductBill> selectRefundProductBillList(RefundProductBill refundProductBill) {
        return refundProductBillMapper.selectRefundProductBillList(refundProductBill);
    }

    /**
     * 新增退料单
     *
     * @param refundProductBill 退料单
     * @return 结果
     */
    @Override
    public int insertRefundProductBill(RefundProductBill refundProductBill) {
        if(refundProductBill==null){
            throw new ServiceException("数据对象为空");
        }
        if (StringUtils.isEmpty(refundProductBill.getStorehouseNo())){
            throw new ServiceException("线边仓不能为空");
        }
        if (StringUtils.isBlank(refundProductBill.getNo())) {
            refundProductBill.setNo(PrefixConstants.RETURN_OF_MATERIAL+TableNoUtil.getNo(RefundProductBill.class));
        }
        refundProductBill.setStorehouseNo(refundProductBill.getStorehouseNo());
        refundProductBill.setStorehouseName(refundProductBill.getStorehouseName());
        refundProductBill.setCreateBy(SecurityUtils.getUsername());
        refundProductBill.setCreateTime(DateUtils.getNowDate());
        refundProductBill.setStatus(InOrderStatusEnum.NEW.getCode());
        List<RefundProductBillDetail> productBillDetailList = refundProductBill.getRefundProductBillDetailList();
        if (CollUtil.isNotEmpty(productBillDetailList)){
            productBillDetailList.stream().forEach(e->{
                e.setNo(TableNoUtil.getNo(RefundProductBillDetail.class));
                e.setBillNo(refundProductBill.getNo());
                e.setCreateBy(SecurityUtils.getUsername());
                e.setCreateTime(DateUtils.getNowDate());
            });
            //汇总数量
            refundProductBill.setTotalQty(refundProductBill.getRefundProductBillDetailList().stream().filter(e->e.getQty()!=null).mapToLong(e -> e.getQty()).sum());
            //生成物料清单
            refundProductBill.getRefundProductBillDetailList().stream().forEach(e->{
               WmsProduct product = wmsProductService.selectWmsProductByProductNo(e.getProductNo());
                e.setProductUnit(product.getCompany());
            });
            this.refundProductBillDetailService.batchInsertRefundProductBillDetail(refundProductBill.getRefundProductBillDetailList());
        }
        //生成退料申请单
        int i = refundProductBillMapper.insertRefundProductBill(refundProductBill);
        //生成退料入库单
        WmsInStockOrder wmsInStockOrder = new WmsInStockOrder();
        wmsInStockOrder.setNo(TableNoUtil.getNo(WmsInStockOrder.class));
        wmsInStockOrder.setRelOrderNo(refundProductBill.getNo());
        wmsInStockOrder.setOrderType(InStockOrderTypeEnum.STORES_RETURNED.getCode());
        wmsInStockOrder.setArea(refundProductBill.getArea());
        wmsInStockOrder.setOrderStatus(InOrderStatusEnum.NEW.getCode());
        wmsInStockOrderService.insertWmsInStockOrder(wmsInStockOrder);
        List<WmsInStockDetailOrder> stockDetailOrders = new ArrayList<>();
        for (RefundProductBillDetail refundProductBillDetail : productBillDetailList) {
            WmsInStockDetailOrder detailOrder = new WmsInStockDetailOrder();
            detailOrder.setOrderNo(wmsInStockOrder.getNo());
            detailOrder.setProductNo(refundProductBillDetail.getProductNo());
            detailOrder.setOrderDetailStatus(InOrderStatusEnum.NEW.getCode());
            detailOrder.setOrderQty(refundProductBillDetail.getQty());
            stockDetailOrders.add(detailOrder);
        }
        if (CollUtil.isNotEmpty(stockDetailOrders)) {
            wmsInStockDetailOrderService.batchInsertInStockDetailOrder(stockDetailOrders);
        }
        return i;
    }

    /**
     * 批量新增退料单
     *
     * @param refundProductBillList 退料单列表
     * @return 结果
     */
    @Override
    public int batchInsertRefundProductBill(List<RefundProductBill> refundProductBillList) {
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (RefundProductBill refundProductBill : refundProductBillList) {
            if (StringUtils.isBlank(refundProductBill.getNo())) {
                refundProductBill.setNo(TableNoUtil.getNo(RefundProductBill.class));
            }
            refundProductBill.setCreateBy(username);
            refundProductBill.setCreateTime(currerTime);
        }
        int insertNum = 0;
        for (int i = 0; i < refundProductBillList.size(); ) {
            int endIndex = i + 500;
            if (endIndex > refundProductBillList.size()) {
                endIndex = refundProductBillList.size();
            }
            insertNum = insertNum + refundProductBillMapper.batchInsertRefundProductBill(refundProductBillList.subList(i, endIndex));
            i = endIndex;
        }
        return insertNum;
    }

    /**
     * 修改退料单
     *
     * @param refundProductBill 退料单
     * @return 结果
     */
    @Override
    public int updateRefundProductBill(RefundProductBill refundProductBill) {
        refundProductBill.setUpdateBy(SecurityUtils.getUsername());
        refundProductBill.setUpdateTime(DateUtils.getNowDate());
        return refundProductBillMapper.updateRefundProductBill(refundProductBill);
    }

    /**
     * 批量修改退料单
     *
     * @param refundProductBillList 退料单列表
     * @return 结果
     */
    @Override
    public int batchUpdateRefundProductBill(List<RefundProductBill> refundProductBillList) {
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (RefundProductBill refundProductBill : refundProductBillList) {
            refundProductBill.setUpdateBy(username);
            refundProductBill.setUpdateTime(currerTime);
        }
        int updateNum = 0;
        for (int i = 0; i < refundProductBillList.size(); ) {
            int endIndex = i + 500;
            if (endIndex > refundProductBillList.size()) {
                endIndex = refundProductBillList.size();
            }
            updateNum = updateNum + refundProductBillMapper.batchUpdateRefundProductBill(refundProductBillList.subList(i, endIndex));
            i = endIndex;
        }
        return updateNum;
    }

    /**
     * 批量删除退料单
     *
     * @param ids 需要删除的退料单主键集合
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteRefundProductBillByIds(Long[] ids) {
        RefundProductBill bill = new RefundProductBill();
        bill.setIds(CollUtil.toList(ids));
        List<RefundProductBill> billList = this.selectRefundProductBillList(bill);

        List<String> nos = billList.stream()
                .filter(e -> InOrderStatusEnum.CANCEL_PENDING_CONFIRMATION.getCode().equals(e.getStatus())
                        || InOrderStatusEnum.ACCOMPLISH.getCode().equals(e.getStatus()))
                .map(RefundProductBill::getNo).collect(Collectors.toList());
        if(!nos.isEmpty()){
            throw new ServiceException("取消待确认或已完成状态的单据不能删除");
        }
        for (RefundProductBill productBill : billList) {
            if(InOrderStatusEnum.PICKING.getCode().equals(productBill.getStatus())){
                //校验进行中单据下的出入库单数据
                WmsInStockOrder stockOrder = wmsInStockOrderService.selectWmsInStockOrderByRelOrderNo(productBill.getNo(), InStockOrderTypeEnum.STORES_RETURNED.getCode());
                if(stockOrder != null && stockOrder.getTotalActualQty() > 0){
                    nos.add(productBill.getNo());
                }
            }
        }
        if(!nos.isEmpty()){
            throw new ServiceException(nos + "单据已有实际入库数量不能删除");
        }
        //入库单和入库单明细删除
        nos = billList.stream().map(RefundProductBill::getNo).collect(Collectors.toList());
        wmsInStockOrderService.deleteWmsInStockOrderByRelOrderNosAndType(nos, InStockOrderTypeEnum.STORES_RETURNED.getCode());

        return refundProductBillMapper.deleteRefundProductBillByIds(ids);
    }

    /**
     * 删除退料单信息
     *
     * @param id 退料单主键
     * @return 结果
     */
    @Override
    public int deleteRefundProductBillById(Long id) {
        return refundProductBillMapper.deleteRefundProductBillById(id);
    }

    /**
     * 查询退料单
     *
     * @param no 编号
     * @return 退料单
     */
    @Override
    public RefundProductBill selectRefundProductBillByNo(String no) {
        return refundProductBillMapper.selectRefundProductBillByNo(no);
    }

    /**
     * 批量删除退料单
     *
     * @param nos 需要删除的编号集合
     * @return 结果
     */
    @Override
    public int deleteRefundProductBillByNos(String[] nos) {
        return refundProductBillMapper.deleteRefundProductBillByNos(nos);
    }

    /**
     * 删除退料单信息
     *
     * @param no 编号
     * @return 结果
     */
    @Override
    public int deleteRefundProductBillByNo(String no) {
        return refundProductBillMapper.deleteRefundProductBillByNo(no);
    }

    @Override
    public int addWithDetail(RefundProductBillVo refundProductBillVo) {
        List<RefundProductBillDetail> refundProductBillDetailList = refundProductBillVo.getRefundProductBillDetailList();
        RefundProductBill refundProductBill = BeanUtil.toBean(refundProductBillVo, RefundProductBill.class);
        refundProductBill.setTotalQty(refundProductBillDetailList.stream().filter(e->e.getQty()!=null).mapToLong(e -> e.getQty()).sum());
        this.insertRefundProductBill(refundProductBill);
        if (CollUtil.isNotEmpty(refundProductBillDetailList)){
            refundProductBillDetailList.forEach(e -> e.setBillNo(refundProductBill.getNo()));
            refundProductBillDetailService.batchInsertRefundProductBillDetail(refundProductBillDetailList);
        }
        //todo 生产入库单
        return 1;
    }

    @Override
    public List<RefundProductBillExportVo> exportList(RefundProductBill refundProductBill) {
        return refundProductBillMapper.exportList(refundProductBill);
    }

    @Override
    @Transactional
    public int cancel(List<Long> ids) {
        RefundProductBill bill = new RefundProductBill();
        bill.setIds(ids);
        List<RefundProductBill> billList = this.selectRefundProductBillList(bill);
        billList = billList.stream().filter(e -> InOrderStatusEnum.NEW.getCode().equals(e.getStatus())
                || InOrderStatusEnum.PICKING.getCode().equals(e.getStatus())).collect(Collectors.toList());
        if (billList.isEmpty()) {
            return 0;
        }
        for (RefundProductBill refundProductBill : billList) {
            WmsInStockOrder wmsInStockOrder = wmsInStockOrderService.selectWmsInStockOrderByRelOrderNo(refundProductBill.getNo(), InStockOrderTypeEnum.SALES_REFUND.getCode());
            if (wmsInStockOrder!=null) {
                if (wmsInStockOrder.getTotalActualQty() > 0){
                    throw new ServiceException("已入库不允许取消，单号：" + refundProductBill.getNo());
                }
                wmsInStockOrder.setOrderStatus(InOrderStatusEnum.CANCEL.getCode());
                this.wmsInStockOrderService.updateWmsInStockOrder(wmsInStockOrder);
            }
        }
        billList.stream().forEach(e -> e.setStatus(InOrderStatusEnum.CANCEL.getCode()));
        this.batchUpdateRefundProductBill(billList);
        return billList.size();
    }

    /**
     * 确认取消
     * @param bill 单据信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int confirmCancel(RefundProductBill bill) {
        bill = this.selectRefundProductBillById(bill.getId());
        if(bill == null){
            throw new ServiceException("单据不存在");
        }else if(!InOrderStatusEnum.CANCEL_PENDING_CONFIRMATION.getCode().equals(bill.getStatus())){
            throw new ServiceException("该状态不是取消待确认，无法确认取消");
        }

        WmsInStockOrder stockOrder = wmsInStockOrderService.selectWmsInStockOrderByRelOrderNo(bill.getNo(), InStockOrderTypeEnum.SALES_REFUND.getCode());
        if(stockOrder != null){
            stockOrder.setOrderStatus(InOrderStatusEnum.CANCEL.getCode());
            wmsInStockOrderService.updateWmsInStockOrder(stockOrder);
        }
        bill.setStatus(InOrderStatusEnum.CANCEL.getCode());
        return this.updateRefundProductBill(bill);
    }
}
